﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Win32;

namespace ContentFinder
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private Regex content;
        private bool matchCase = false;
        private bool enableRegex = true;

        private string progressStr = "Finding ...";
        private string totalFoundFormat = "Total found {0} results(s) at {1}";
        private string savedFileFormat = "Saved {0} results(s) in {1}";
        private string usageInFileFormat = "Usage:{0}\r\nFile:{1}\r\nLine:{2}\r\n\r\n";

        private void search_Click(object sender, RoutedEventArgs e)
        {
            Log.Clear();
            string[] xmlFileDir = tbPath.Text.Trim().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
            content = new Regex(tbContent.Text.Trim());
            ProcessEveryFolder(xmlFileDir);
        }

        private void ProcessEveryFolder(string[] args)
        {
            Task<List<ContentUsage>>[] tasks = new Task<List<ContentUsage>>[args.Length];
            var ui = TaskScheduler.FromCurrentSynchronizationContext();
            List<ContentUsage> result = new List<ContentUsage>();
            for (int i = 0; i < args.Length; i++)
            {
                string tmp = args[i];
                int j = i;

                tasks[j] = Task.Factory.StartNew<List<ContentUsage>>(() =>
                {
                    return GetContainsMyContent(tmp);
                });

                tasks[j].ContinueWith(resultTask =>
                    result.AddRange(tasks[j].Result), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ui);

            }
            Task.Factory.ContinueWhenAll<List<ContentUsage>>(tasks,
                completedTasks =>
                {
                    lvResult.ItemsSource = result;
                    lbStatus.Content = string.Format(totalFoundFormat, result.Count, DateTime.Now.ToString());
                }, CancellationToken.None, TaskContinuationOptions.None, ui);
        }

        private List<ContentUsage> GetContainsMyContent(string arg)
        {
            List<ContentUsage> allFileList = new List<ContentUsage>();
            FileSystemInfo[] allFile;
            try
            {
                allFile = (new DirectoryInfo(arg)).GetFileSystemInfos("*.*", SearchOption.AllDirectories);
            }
            catch (Exception ex)
            {
                Log.Failure(ex.Message);
                return new List<ContentUsage>();
            }
            List<ContentUsage> returnValue = new List<ContentUsage>(); ;
            foreach (var item in allFile)
            {
                string fileType = "ContentFinder.SupportSuffix" + item.Extension.ToUpperInvariant() + "Class";
                Type type = Type.GetType(fileType);
                if (type != null)
                {
                    object SuffixClass = Activator.CreateInstance(type);
                    MethodInfo GetAllContent = type.GetMethod("GetAllContent");
                    BindingFlags flag = BindingFlags.Public | BindingFlags.Instance;
                    object[] parameters = new object[] { item.FullName, content.ToString(), matchCase };
                    returnValue = (List<ContentUsage>)GetAllContent.Invoke(SuffixClass, flag, Type.DefaultBinder, parameters, null);
                }
                else
                {
                    Log.Failure(string.Format("Not Support Sufffix : {0}", item.Extension.TrimStart('.')));
                }
                allFileList = allFileList.Union(returnValue).ToList();
            }
            return allFileList;
        }

        private void tbContent_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Enter)
            {
                lvResult.ItemsSource = null;
                lvResult.Items.Clear();
                search_Click(sender, new RoutedEventArgs());
                lbStatus.Content = progressStr;
            }
        }

        private void lvResult_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ContentUsage contentUsage = (ContentUsage)((sender as System.Windows.Controls.ListView).SelectedItem);
            if (contentUsage != null)
            {
                string fileFullname = contentUsage.FileFullname;
                string fileType = "ContentFinder.SupportSuffix" + contentUsage.FileSuffix + "Class";
                Type type = Type.GetType(fileType);
                if (type != null)
                {
                    object SuffixClass = Activator.CreateInstance(type);
                    MethodInfo OpenFile = type.GetMethod("OpenFile");
                    BindingFlags flag = BindingFlags.Public | BindingFlags.Instance;
                    object[] parameters = new object[] { fileFullname };
                    OpenFile.Invoke(SuffixClass, flag, Type.DefaultBinder, parameters, null);
                }
            }
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Controls.MenuItem item = sender as System.Windows.Controls.MenuItem;
            if (item != null)
            {
                switch (item.Header.ToString())
                {
                    case "Match Case": matchCase = item.IsChecked; break;
                    case "Enable Regex": enableRegex = item.IsChecked; break;
                    default:
                        Log.Failure(string.Format("Don't found this MenuItem", item.Header.ToString()));
                        break;
                }
            }
        }

        private void FinderWebsite_Click(object sender, RoutedEventArgs e)
        {
            Process.Start("http://contentfinder.codeplex.com/");
        }

        private void ContactAuthor_Click(object sender, RoutedEventArgs e)
        {
            Process.Start("mailto:henanlinzhoulcl@163.com");
        }

        /// <summary>
        /// click the export and store all of the searched item into txt.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Export_Click(object sender, RoutedEventArgs e)
        {
            if (lvResult.HasItems)
            {
                SaveFileDialog saveDig = new SaveFileDialog();
                saveDig.Filter = @"(*.txt)|*.txt";
                saveDig.FileName = "*.txt";
                if (saveDig.ShowDialog() == true)
                {
                    StreamWriter sw = new StreamWriter(saveDig.FileName, false, System.Text.Encoding.Default);                  
                    foreach (ContentFinder.ContentUsage item in lvResult.Items)
                    {
                        sw.Write(string.Format(usageInFileFormat,item.Usage,item.FileFullname,item.LineNum));                     
                    }
                    sw.Close();
                    lbStatus.Content = string.Format(savedFileFormat, lvResult.Items.Count, saveDig.FileName);
                }
            }
        }

        private void Close_Click(object sender, RoutedEventArgs e)
        {
            Environment.Exit(0);
        }
    }
}
